#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <jni.h>
#include <leds_hal.h>
/**这里说明一下为什么这里的leds_hal.h文件会用尖括号<...>,这是因为该文件属于HAL的源代码文件，其路径在hardware/leds_hal上，且在其对应的Android.mk文件中指定，因此该文件便属于系统文件，所以需要用尖括号表示。*/
struct led_control_device_t *led_hal_device = NULL;
/**定义led_control_device_t结构体指针，后面的led_control_open函数会用到。这个结构体包含了HAL模块中许多重要函数，像后面要调用的set_on和set_off等*/
static jboolean led_setOn(JNIEnv* env, jobject thiz, jint led)
{
    LOGI("Led HAL JNI: led_setOn() is invoked.");

    if (led_hal_device == NULL)
    {
        LOGI("Led HAL JNI: led_hal_device was not fetched correctly.");
        return -1;
    }
    else
    {
        return led_hal_device->set_on(led_hal_device, led);
    }
}

static jboolean led_setOff(JNIEnv* env, jobject thiz, jint led)
{
    LOGI("Led HAL JNI: led_setOff() is invoked.");
    if (led_hal_device == NULL)
    {
        LOGI("Led HAL JNI: led_hal_device was not fetched correctly.");
        return -1;
    }
    else
    {
        return led_hal_device->set_off(led_hal_device, led);
    }
}
//定义一个内敛函数，以调用HAL的open方法
static inline int led_control_open(const struct hw_module_t* module,
        struct led_control_device_t** device)
{
    return module->methods->open(module, LED_HARDWARE_MODULE_ID,
            (struct hw_device_t**) device);
}

static jboolean led_init(JNIEnv *env, jclass clazz)
{
    led_module_t* module;

    LOGE("**********start find hal *********");
    LOGE(LED_HARDWARE_MODULE_ID);
/**通过该函数以及HAL的ID号，返回相应的hw_module_t指针，hw_get_module函数在hardware.c中定义*/
    if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**) &module)
            == 0)
    {
        LOGI("LedService JNI: LED Stub found.");
        if (led_control_open(&module->hw_module, &led_hal_device) == 0)
        {
            LOGI("LedService JNI: Got Stub operations.");
            return 0;
        }
    }

    LOGE("LedService JNI: Get Stub operations failed.");
    return -1;
}

/**与上层的Java库进行方法映射，即定义一个method数组。如果不使用这种方法映射的方式的话，就要使用JNI的特殊命名方式，之前我们在写CC1101的时候就是采用的那种方式。*/
static const JNINativeMethod methods[] =
{
{ "_init", "()Z", (void *) led_init },
{ "_set_on", "(I)Z", (void *) led_setOn },
{ "_set_off", "(I)Z", (void *) led_setOff }, };

/**通过上面的映射之外，我们还需要RegisterNative注册，才能发挥效力*/
int register_led_hal_jni(JNIEnv* env)
{
//这里要事先定义好Java库的路径
    static const char* const kClassName = "mobile/android/leds/hal/service/LedHalService";

    jclass clazz;

    clazz = env->FindClass(kClassName);
    if (clazz == NULL)
    {
        LOGE("Can't find class %s\n", kClassName);
        return -1;
    }
    if (env->RegisterNatives(clazz, methods,
            sizeof(methods) / sizeof(methods[0])) != JNI_OK)
    {
        LOGE("Failed registering methods for %s\n", kClassName);
        return -1;
    }

    return 0;
}

/**通过该函数，会初始化该JNI模块*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
    {
        LOGE("GetEnv failed!");
        return result;
    }

    register_led_hal_jni(env);

    return JNI_VERSION_1_4;
}